/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.gen2phen.labs.services;

import com.hp.hpl.jena.query.DatasetFactory;
import com.hp.hpl.jena.query.QueryExecution;
import com.hp.hpl.jena.query.QueryExecutionFactory;
import com.hp.hpl.jena.query.QuerySolution;
import com.hp.hpl.jena.query.ResultSet;
import com.hp.hpl.jena.query.Syntax;
import java.util.HashMap;
import org.gen2phen.labs.domain.Disease;
import org.gen2phen.labs.domain.Drug;
import org.gen2phen.labs.domain.Gene;

/**
 *
 * @author pedrolopes
 *
 * GEN2PHEN Semantic Web Labs: Knowledge Netowork
 *
 */
public class Loader {

    public static HashMap<String, Gene> genes = new HashMap<String, Gene>();
    public static HashMap<String, Disease> diseases = new HashMap<String, Disease>();
    public static HashMap<String, Drug> drugs = new HashMap<String, Drug>();

    public static HashMap<String, Disease> getDiseases() {
        return diseases;
    }

    public static void setDisease(HashMap<String, Disease> disease) {
        Loader.diseases = disease;
    }

    public static HashMap<String, Drug> getDrugs() {
        return drugs;
    }

    public static void setDrugs(HashMap<String, Drug> drugs) {
        Loader.drugs = drugs;
    }

    public static HashMap<String, Gene> getGenes() {
        return genes;
    }

    public static void setGenes(HashMap<String, Gene> genes) {
        Loader.genes = genes;
    }

    /**
     * Uses federated querying to connect to multiple SPARQL endpoints all load required information associated
     * with the given gene HGNC symbol.
     *
     * @param gene The Gene.
     * @return Success of the operation.
     */
    public static boolean loadByGene(String gene) {
        boolean success = false;

        // test if gene has already been loaded
        if (!genes.containsKey(gene)) {
            Gene g = new Gene(gene);
            try {

                // start federated querying workflow
                //  1 - search Diseasome for diseases associated with the given gene
                //  2 - load information about Diseases
                //  3 - search for possible drugs associated with found Diseases
                //  4 - search DrugBank and DailyMed for possible drug matches
                //  5 - merge and normalizae DrugBank and DailyMed drug information
                //  6 - connect all data to main SELECT

                String prefix = "PREFIX d2r: <http://sites.wiwiss.fu-berlin.de/suhl/bizer/d2r-server/config.rdf#>"
                        + "PREFIX dailymed: <http://www4.wiwiss.fu-berlin.de/dailymed/resource/dailymed/> "
                        + "PREFIX vocabClass: <http://www4.wiwiss.fu-berlin.de/drugbank/vocab/resource/class/> "
                        + "PREFIX xsd: <http://www.w3.org/2001/XMLSchema#> "
                        + "PREFIX diseasome: <http://www4.wiwiss.fu-berlin.de/diseasome/resource/diseasome/> "
                        + "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> "
                        + "PREFIX foaf: <http://xmlns.com/foaf/0.1/> "
                        + "PREFIX owl: <http://www.w3.org/2002/07/owl#> "
                        + "PREFIX vocabProperty: <http://www4.wiwiss.fu-berlin.de/drugbank/vocab/resource/property/> "
                        + "PREFIX db: <http://www4.wiwiss.fu-berlin.de/diseasome/resource/> "
                        + "PREFIX drugbank: <http://www4.wiwiss.fu-berlin.de/drugbank/resource/drugbank/> "
                        + "PREFIX dbpedia: <http://dbpedia.org/ontology/> "
                        + "PREFIX map: <file:/C:/apps/diseasome/diseasome.n3#> "
                        + "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>"
                        + "PREFIX dbpedia2: <http://dbpedia.org/property/>"
                        + "PREFIX skos: <http://www.w3.org/2004/02/skos/core#>"
                        + "PREFIX dbpedia-owl: <http://dbpedia.org/ontology>";

                String query = prefix + "SELECT ?drugname ?name ?diseasename ?diseaseomim ?pharma ?diseaseclass ?indication ?description {"
                        + "{ SERVICE <http://www4.wiwiss.fu-berlin.de/diseasome/sparql> "
                        + " { SELECT ?drug ?diseasename ?diseaseomim ?diseaseclass WHERE { "
                        + "  ?gene rdfs:label \"" + gene + "\" ."
                        + "  ?disease diseasome:associatedGene ?gene ."
                        + "  ?disease diseasome:omim ?diseaseomim ."
                        + "  ?disease diseasome:name ?diseasename ."
                        + "  ?disease diseasome:class ?diseaseclass ."
                        + "  ?disease diseasome:possibleDrug ?drug"
                        + "}"
                        + " }"
                        + "}"
                        + "{"
                        + "{ SERVICE <http://www4.wiwiss.fu-berlin.de/drugbank/sparql>"
                        + " { SELECT ?drugname ?description ?pharma ?indication WHERE {"
                        + "   ?drug drugbank:genericName ?drugname ."
                        + "   ?drug drugbank:description ?description ."
                        + "   ?drug drugbank:pharmacology ?pharma ."
                        + "   ?drug drugbank:indication ?indication"
                        + " }"
                        + "}"
                        + "}"
                        + " UNION "
                        + "{ SERVICE <http://www4.wiwiss.fu-berlin.de/dailymed/sparql>"
                        + " { SELECT ?drugname ?description ?pharma ?indication WHERE {"
                        + "   ?drug dailymed:name ?drugname ."
                        + "   ?drug dailymed:description ?description ."
                        + "   ?drug dailymed:indication ?indication ."
                        + "   ?drug dailymed:clinicalPharmacology ?pharma"
                        + " }"
                        + "}"
                        + "}"
                        + "}"
                        + "}";

                QueryExecution e = QueryExecutionFactory.create(query, Syntax.syntaxARQ, DatasetFactory.create());
                ResultSet rs = e.execSelect();

                // process results
                //  1 - create new disease and add it to gene
                //  2 - add disease to general disease list (if not there already)
                //  3 - create new drug and associate it with disease
                //  4 - add drug to general drug list (if not there already)
                while (rs.hasNext()) {
                    QuerySolution row = rs.nextSolution();

                    Disease dis = new Disease();
                    Drug drug = new Drug();

                    if (!g.diseases.containsKey(row.get("diseasename").toString())) {
                        dis = new Disease(row.get("diseasename").toString(), getOmim(row.get("diseaseomim").toString()), getClass(row.get("diseaseclass").toString()));
                        g.addDisease(dis);

                    } else {
                        dis = g.diseases.get(row.get("diseasename").toString());

                    }
                    diseases.put(row.get("diseasename").toString(), dis);
                    if (!dis.drugs.containsKey(row.get("drugname").toString())) {
                        drug = new Drug(row.get("description").toString(), row.get("drugname").toString(), row.get("pharma").toString(), row.get("indication").toString());
                        dis.addDrug(drug);
                    }
                    drugs.put(row.get("drugname").toString(), drug);

                }
                genes.put(gene, g);
                success = true;
            } catch (Exception e) {
                System.out.println("[Loader] error " + e.toString());
            }
        } else {
            success = true;
        }

        return success;
    }

    /**
     * Helper method to get an OMIM ID from Diseasome formatted results.
     *
     * @param address
     * @return
     */
    static int getOmim(String address) {
        String[] omims = address.toString().split(":");
        return Integer.parseInt(omims[omims.length - 1]);
    }

    /**
     * Helper method to get a disease class from Diseasome formatted results.
     * 
     * @param address
     * @return
     */
    static String getClass(String address) {
        String[] classes = address.toString().split("/");
        return classes[classes.length - 1].replace("_", " ");
    }
}
